home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ADA Programming Guide
/
ADA Programming Guide.iso
/
ada_lrm
/
chap05.doc
< prev
next >
Wrap
Text File
|
1996-01-30
|
28KB
|
748 lines
5. Statements
A statement defines an action to be performed; the process by which a
statement achieves its action is called execution of the statement.
This chapter describes the general rules applicable to all statements.
Some specific statements are discussed in later chapters. Procedure call
statements are described in Chapter 6 on subprograms. Entry call, delay,
accept, select, and abort statements are described in Chapter 9 on tasks.
Raise statements are described in Chapter 11 on exceptions, and code
statements in Chapter 13. The remaining forms of statements are presented
in this chapter.
References: abort statement 9.10, accept statement 9.5, code statement
13.8, delay statement 9.6, entry call statement 9.5, procedure call
statement 6.4, raise statement 11.3, select statement 9.7
5.1 Simple and Compound Statements - Sequences of Statements
A statement is either simple or compound. A simple statement encloses no
other statement. A compound statement can enclose simple statements and
other compound statements.
sequence_of_statements ::= statement {statement}
statement ::=
{label} simple_statement | {label} compound_statement
simple_statement ::= null_statement
| assignment_statement | procedure_call_statement
| exit_statement | return_statement
| goto_statement | entry_call_statement
| delay_statement | abort_statement
| raise_statement | code_statement
compound_statement ::=
if_statement | case_statement
| loop_statement | block_statement
| accept_statement | select_statement
label ::= <<label_simple_name>>
null_statement ::= null;
A statement is said to be labeled by the label name of any label of the
statement. A label name, and similarly a loop or block name, is implicitly
declared at the end of the declarative part of the innermost block
statement, subprogram body, package body, task body, or generic body that
encloses the labeled statement, the named loop statement, or the named
block statement, as the case may be. For a block statement without a
declarative part, an implicit declarative part (and preceding declare) is
assumed.
The implicit declarations for different label names, loop names, and block
names occur in the same order as the beginnings of the corresponding
labeled statements, loop statements, and block statements. Distinct
identifiers must be used for all label, loop, and block names that are
implicitly declared within the body of a program unit, including within
block statements enclosed by this body, but excluding within other enclosed
program units (a program unit is either a subprogram, a package, a task
unit, or a generic unit).
Execution of a null statement has no other effect than to pass to the next
action.
The execution of a sequence of statements consists of the execution of the
individual statements in succession until the sequence is completed, or a
transfer of control takes place. A transfer of control is caused either by
the execution of an exit, return, or goto statement; by the selection of a
terminate alternative; by the raising of an exception; or (indirectly) by
the execution of an abort statement.
Examples of labeled statements:
<<HERE>> <<ICI>> <<AQUI>> <<HIER>> null;
<<AFTER>> X := 1;
Note:
The scope of a declaration starts at the place of the declaration itself
(see 8.2). In the case of a label, loop, or block name, it follows from
this rule that the scope of the implicit declaration starts before the
first explicit occurrence of the corresponding name, since this occurrence
is either in a statement label, a loop statement, a block statement, or a
goto statement. An implicit declaration in a block statement may hide a
declaration given in an outer program unit or block statement (according to
the usual rules of hiding explained in section 8.3).
References: abort statement 9.10, accept statement 9.5, assignment
statement 5.2, block name 5.6, block statement 5.6, case statement 5.4,
code statement 13.8, declaration 3.1, declarative part 3.9, delay statement
9.6, entry call statement 9.5, exception 11, exit statement 5.7, generic
body 12.1, generic unit 12, goto statement 5.9, hiding 8.3, identifier 2.3,
if statement 5.3, implicit declaration 3.1, loop name 5.5, loop statement
5.5, package 7, package body 7.1, procedure call statement 6.4, program
unit 6, raise statement 11.3, raising of exceptions 11, return statement
5.8, scope 8.2, select statement 9.7, simple name 4.1, subprogram 6,
subprogram body 6.3, task 9, task body 9.1, task unit 9.1, terminate
alternative 9.7.1, terminated task 9.4
5.2 Assignment Statement
An assignment statement replaces the current value of a variable with a new
value specified by an expression. The named variable and the right-hand
side expression must be of the same type; this type must not be a limited
type.
assignment_statement ::=
variable_name := expression;
For the execution of an assignment statement, the variable name and the
expression are first evaluated, in some order that is not defined by the
language. A check is then made that the value of the expression belongs to
the subtype of the variable, except in the case of a variable that is an
array (the assignment then involves a subtype conversion as described in
section 5.2.1). Finally, the value of the expression becomes the new value
of the variable.
The exception CONSTRAINT_ERROR is raised if the above-mentioned subtype
check fails; in such a case the current value of the variable is left
unchanged. If the variable is a subcomponent that depends on discriminants
of an unconstrained record variable, then the execution of the assignment
is erroneous if the value of any of these discriminants is changed by this
execution.
Examples:
VALUE := MAX_VALUE - 1;
SHADE := BLUE;
NEXT_FRAME(F)(M, N) := 2.5; -- see 4.1.1
U := DOT_PRODUCT(V, W); -- see 6.5
WRITER := (STATUS => OPEN, UNIT => PRINTER, LINE_COUNT => 60); -- see 3.7.3
NEXT_CAR.all := (72074, null); -- see 3.8.1
Examples of constraint checks:
I, J : INTEGER range 1 .. 10;
K : INTEGER range 1 .. 20;
...
I := J; -- identical ranges
K := J; -- compatible ranges
J := K; -- will raise the exception CONSTRAINT_ERROR if K > 10
Notes:
The values of the discriminants of an object designated by an access value
cannot be changed (not even by assigning a complete value to the object
itself) since such objects, created by allocators, are always constrained
(see 4.8); however, subcomponents of such objects may be unconstrained.
If the right-hand side expression is either a numeric literal or named
number, or an attribute that yields a result of type universal_integer or
universal_real, then an implicit type conversion is performed, as described
in section 4.6.
The determination of the type of the variable of an assignment statement
may require consideration of the expression if the variable name can be
interpreted as the name of a variable designated by the access value
returned by a function call, and similarly, as a component or slice of such
a variable (see section 8.7 for the context of overload resolution).
References: access type 3.8, allocator 4.8, array 3.6, array assignment
5.2.1, component 3.6 3.7, constraint_error exception 11.1, designate 3.8,
discriminant 3.7.1, erroneous 1.6, evaluation 4.5, expression 4.4, function
call 6.4, implicit type conversion 4.6, name 4.1, numeric literal 2.4,
object 3.2, overloading 6.6 8.7, slice 4.1.2, subcomponent 3.3, subtype
3.3, subtype conversion 4.6, type 3.3, universal_integer type 3.5.4,
universal_real type 3.5.6, variable 3.2.1
5.2.1 Array Assignments
If the variable of an assignment statement is an array variable (including
a slice variable), the value of the expression is implicitly converted to
the subtype of the array variable; the result of this subtype conversion
becomes the new value of the array variable.
This means that the new value of each component of the array variable is
specified by the matching component in the array value obtained by
evaluation of the expression (see 4.5.2 for the definition of matching
components). The subtype conversion checks that for each component of the
array variable there is a matching component in the array value, and vice
versa. The exception CONSTRAINT_ERROR is raised if this check fails; in
such a case the value of each component of the array variable is left
unchanged.
Examples:
A : STRING(1 .. 31);
B : STRING(3 .. 33);
...
A := B; -- same number of components
A(1 .. 9) := "tar sauce";
A(4 .. 12) := A(1 .. 9); -- A(1 .. 12) = "tartar sauce"
Notes:
Array assignment is defined even in the case of overlapping slices, because
the expression on the right-hand side is evaluated before performing any
component assignment. In the above example, an implementation yielding A(1
.. 12) = "tartartartar" would be incorrect.
The implicit subtype conversion described above for assignment to an array
variable is performed only for the value of the right-hand side expression
as a whole; it is not performed for subcomponents that are array values.
References: array 3.6, assignment 5.2, constraint_error exception 11.1,
matching array components 4.5.2, slice 4.1.2, subtype conversion 4.6, type
3.3, variable 3.2.1
5.3 If Statements
An if statement selects for execution one or none of the enclosed sequences
of statements, depending on the (truth) value of one or more corresponding
conditions.
if_statement ::=
if condition then
sequence_of_statements
{elsif condition then
sequence_of_statements}
[else
sequence_of_statements]
end if;
condition ::= boolean_expression
An expression specifying a condition must be of a boolean type.
For the execution of an if statement, the condition specified after if, and
any conditions specified after elsif, are evaluated in succession (treating
a final else as elsif TRUE then), until one evaluates to TRUE or all
conditions are evaluated and yield FALSE. If one condition evaluates to
TRUE, then the corresponding sequence of statements is executed; otherwise
none of the sequences of statements is executed.
Examples:
if MONTH = DECEMBER and DAY = 31 then
MONTH := JANUARY;
DAY := 1;
YEAR := YEAR + 1;
end if;
if LINE_TOO_SHORT then
raise LAYOUT_ERROR;
elsif LINE_FULL then
NEW_LINE;
PUT(ITEM);
else
PUT(ITEM);
end if;
if MY_CAR.OWNER.VEHICLE /= MY_CAR then -- see 3.8
REPORT ("Incorrect data");
end if;
References: boolean type 3.5.3, evaluation 4.5, expression 4.4, sequence
of statements 5.1
5.4 Case Statements
A case statement selects for execution one of a number of alternative
sequences of statements; the chosen alternative is defined by the value of
an expression.
case_statement ::=
case expression is
case_statement_alternative
{case_statement_alternative}
end case;
case_statement_alternative ::=
when choice {| choice } =>
sequence_of_statements
The expression must be of a discrete type which must be determinable
independently of the context in which the expression occurs, but using the
fact that the expression must be of a discrete type. Moreover, the type of
this expression must not be a generic formal type. Each choice in a case
statement alternative must be of the same type as the expression; the list
of choices specifies for which values of the expression the alternative is
chosen.
If the expression is the name of an object whose subtype is static, then
each value of this subtype must be represented once and only once in the
set of choices of the case statement, and no other value is allowed; this
rule is likewise applied if the expression is a qualified expression or
type conversion whose type mark denotes a static subtype. Otherwise, for
other forms of expression, each value of the (base) type of the expression
must be represented once and only once in the set of choices, and no other
value is allowed.
The simple expressions and discrete ranges given as choices in a case
statement must be static. A choice defined by a discrete range stands for
all values in the corresponding range (none if a null range). The choice
others is only allowed for the last alternative and as its only choice; it
stands for all values (possibly none) not given in the choices of previous
alternatives. A component simple name is not allowed as a choice of a case
statement alternative.
The execution of a case statement consists of the evaluation of the
expression followed by the execution of the chosen sequence of statements.
Examples:
case SENSOR is
when ELEVATION => RECORD_ELEVATION(SENSOR_VALUE);
when AZIMUTH => RECORD_AZIMUTH (SENSOR_VALUE);
when DISTANCE => RECORD_DISTANCE (SENSOR_VALUE);
when others => null;
end case;
case TODAY is
when MON => COMPUTE_INITIAL_BALANCE;
when FRI => COMPUTE_CLOSING_BALANCE;
when TUE .. THU => GENERATE_REPORT(TODAY);
when SAT .. SUN => null;
end case;
case BIN_NUMBER(COUNT) is
when 1 => UPDATE_BIN(1);
when 2 => UPDATE_BIN(2);
when 3 | 4 =>
EMPTY_BIN(1);
EMPTY_BIN(2);
when others => raise ERROR;
end case;
Notes:
The execution of a case statement chooses one and only one alternative,
since the choices are exhaustive and mutually exclusive. Qualification of
the expression of a case statement by a static subtype can often be used to
limit the number of choices that need be given explicitly.
An others choice is required in a case statement if the type of the
expression is the type universal_integer (for example, if the expression is
an integer literal), since this is the only way to cover all values of the
type universal_integer.
References: base type 3.3, choice 3.7.3, context of overload resolution
8.7, discrete type 3.5, expression 4.4, function call 6.4, generic formal
type 12.1, conversion 4.6, discrete type 3.5, enumeration literal 3.5.1,
expression 4.4, name 4.1, object 3.2.1, overloading 6.6 8.7, qualified
expression 4.7, sequence of statements 5.1, static discrete range 4.9,
static subtype 4.9, subtype 3.3, type 3.3, type conversion 4.6, type mark
3.3.2
5.5 Loop Statements
A loop statement includes a sequence of statements that is to be executed
repeatedly, zero or more times.
loop_statement ::=
[loop_simple_name:]
[iteration_scheme] loop
sequence_of_statements
end loop [loop_simple_name];
iteration_scheme ::= while condition
| for loop_parameter_specification
loop_parameter_specification ::=
identifier in [reverse] discrete_range
If a loop statement has a loop simple name, this simple name must be given
both at the beginning and at the end.
A loop statement without an iteration scheme specifies repeated execution
of the sequence of statements. Execution of the loop statement is complete
when the loop is left as a consequence of the execution of an exit
statement, or as a consequence of some other transfer of control (see 5.1).
For a loop statement with a while iteration scheme, the condition is
evaluated before each execution of the sequence of statements; if the
value of the condition is TRUE, the sequence of statements is executed, if
FALSE the execution of the loop statement is complete.
For a loop statement with a for iteration scheme, the loop parameter
specification is the declaration of the loop parameter with the given
identifier. The loop parameter is an object whose type is the base type of
the discrete range (see 3.6.1). Within the sequence of statements, the
loop parameter is a constant. Hence a loop parameter is not allowed as the
(left-hand side) variable of an assignment statement. Similarly the loop
parameter must not be given as an out or in out parameter of a procedure or
entry call statement, or as an in out parameter of a generic instantiation.
For the execution of a loop statement with a for iteration scheme, the loop
parameter specification is first elaborated. This elaboration creates the
loop parameter and evaluates the discrete range.
If the discrete range is a null range, the execution of the loop statement
is complete. Otherwise, the sequence of statements is executed once for
each value of the discrete range (subject to the loop not being left as a
consequence of the execution of an exit statement or as a consequence of
some other transfer of control). Prior to each such iteration, the
corresponding value of the discrete range is assigned to the loop
parameter. These values are assigned in increasing order unless the
reserved word reverse is present, in which case the values are assigned in
decreasing order.
Example of a loop statement without an iteration scheme:
loop
GET(CURRENT_CHARACTER);
exit when CURRENT_CHARACTER = '*';
end loop;
Example of a loop statement with a while iteration scheme:
while BID(N).PRICE < CUT_OFF.PRICE loop
RECORD_BID(BID(N).PRICE);
N := N + 1;
end loop;
Example of a loop statement with a for iteration scheme:
for J in BUFFER'RANGE loop -- legal even with a null range
if BUFFER(J) /= SPACE then
PUT(BUFFER(J));
end if;
end loop;
Example of a loop statement with a loop simple name:
SUMMATION:
while NEXT /= HEAD loop -- see 3.8
SUM := SUM + NEXT.VALUE;
NEXT := NEXT.SUCC;
end loop SUMMATION;
Notes:
The scope of a loop parameter extends from the loop parameter specification
to the end of the loop statement, and the visibility rules are such that a
loop parameter is only visible within the sequence of statements of the
loop.
The discrete range of a for loop is evaluated just once. Use of the
reserved word reverse does not alter the discrete range, so that the
following iteration schemes are not equivalent; the first has a null
range.
for J in reverse 1 .. 0
for J in 0 .. 1
Loop names are also used in exit statements, and in expanded names (in a
prefix of the loop parameter).
References: actual parameter 6.4.1, assignment statement 5.2, base type
3.3, bound of a range 3.5, condition 5.3, constant 3.2.1, context of
overload resolution 8.7, conversion 4.6, declaration 3.1, discrete range
3.6.1, elaboration 3.1, entry call statement 9.5, evaluation 4.5, exit
statement 5.7, expanded name 4.1.3, false boolean value 3.5.3, generic
actual parameter 12.3, generic instantiation 12.3, goto statement 5.9,
identifier 2.3, integer type 3.5.4, null range 3.5, object 3.2.1, prefix
4.1, procedure call 6.4, raising of exceptions 11, reserved word 2.9,
return statement 5.8, scope 8.2, sequence of statements 5.1, simple name
4.1, terminate alternative 9.7.1, true boolean value 3.5.3 3.5.4,
visibility 8.3
5.6 Block Statements
A block statement encloses a sequence of statements optionally preceded by
a declarative part and optionally followed by exception handlers.
block_statement ::=
[block_simple_name:]
[declare
declarative_part]
begin
sequence_of_statements
[exception
exception_handler
{exception_handler}]
end [block_simple_name];
If a block statement has a block simple name, this simple name must be
given both at the beginning and at the end.
The execution of a block statement consists of the elaboration of its
declarative part (if any) followed by the execution of the sequence of
statements. If the block statement has exception handlers, these service
corresponding exceptions that are raised during the execution of the
sequence of statements (see 11.2).
Example:
SWAP:
declare
TEMP : INTEGER;
begin
TEMP := V; V := U; U := TEMP;
end SWAP;
Notes:
If task objects are declared within a block statement whose execution is
completed, the block statement is not left until all its dependent tasks
are terminated (see 9.4). This rule applies also to a completion caused by
an exit, return, or goto statement; or by the raising of an exception.
Within a block statement, the block name can be used in expanded names
denoting local entities such as SWAP.TEMP in the above example (see 4.1.3
(f)).
References: declarative part 3.9, dependent task 9.4, exception handler
11.2, exit statement 5.7, expanded name 4.1.3, goto statement 5.9, raising
of exceptions 11, return statement 5.8, sequence of statements 5.1, simple
name 4.1, task object 9.2
5.7 Exit Statements
An exit statement is used to complete the execution of an enclosing loop
statement (called the loop in what follows); the completion is conditional
if the exit statement includes a condition.
exit_statement ::=
exit [loop_name] [when condition];
An exit statement with a loop name is only allowed within the named loop,
and applies to that loop; an exit statement without a loop name is only
allowed within a loop, and applies to the innermost enclosing loop (whether
named or not). Furthermore, an exit statement that applies to a given loop
must not appear within a subprogram body, package body, task body, generic
body, or accept statement, if this construct is itself enclosed by the
given loop.
For the execution of an exit statement, the condition, if present, is first
evaluated. Exit from the loop then takes place if the value is TRUE or if
there is no condition.
Examples:
for N in 1 .. MAX_NUM_ITEMS loop
GET_NEW_ITEM(NEW_ITEM);
MERGE_ITEM(NEW_ITEM, STORAGE_FILE);
exit when NEW_ITEM = TERMINAL_ITEM;
end loop;
MAIN_CYCLE:
loop
-- initial statements
exit MAIN_CYCLE when FOUND;
-- final statements
end loop MAIN_CYCLE;
Note:
Several nested loops can be exited by an exit statement that names the
outer loop.
References: accept statement 9.5, condition 5.3, evaluation 4.5, generic
body 12.1, loop name 5.5, loop statement 5.5, package body 7.1, subprogram
body 6.3, true boolean value 3.5.3
5.8 Return Statements
A return statement is used to complete the execution of the innermost
enclosing function, procedure, or accept statement.
return_statement ::= return [expression];
A return statement is only allowed within the body of a subprogram or
generic subprogram, or within an accept statement, and applies to the
innermost (enclosing) such construct; a return statement is not allowed
within the body of a task unit, package, or generic package enclosed by
this construct (on the other hand, it is allowed within a compound
statement enclosed by this construct and, in particular, in a block
statement).
A return statement for an accept statement or for the body of a procedure
or generic procedure must not include an expression. A return statement
for the body of a function or generic function must include an expression.
The value of the expression defines the result returned by the function.
The type of this expression must be the base type of the type mark given
after the reserved word return in the specification of the function or
generic function (this type mark defines the result subtype).
For the execution of a return statement, the expression (if any) is first
evaluated and a check is made that the value belongs to the result subtype.
The execution of the return statement is thereby completed if the check
succeeds; so also is the execution of the subprogram or of the accept
statement. The exception CONSTRAINT_ERROR is raised at the place of the
return statement if the check fails.
Examples:
return; -- in a procedure
return KEY_VALUE(LAST_INDEX); -- in a function
Note:
If the expression is either a numeric literal or named number, or an
attribute that yields a result of type universal_integer or universal_real,
then an implicit conversion of the result is performed as described in
section 4.6.
References: accept statement 9.5, attribute A, block statement 5.6,
constraint_error exception 11.1, expression 4.4, function body 6.3,
function call 6.4, generic body 12.1, implicit type conversion 4.6, named
number 3.2, numeric literal 2.4, package body 7.1, procedure body 6.3,
reserved word 2.9, result subtype 6.1, subprogram body 6.3, subprogram
specification 6.1, subtype 3.3, task body 9.1, type mark 3.3.2,
universal_integer type 3.5.4, universal_real type 3.5.6
5.9 Goto Statements
A goto statement specifies an explicit transfer of control from this
statement to a target statement named by a label.
goto_statement ::= goto label_name;
The innermost sequence of statements that encloses the target statement
must also enclose the goto statement (note that the goto statement can be a
statement of an inner sequence). Furthermore, if a goto statement is
enclosed by an accept statement or the body of a program unit, then the
target statement must not be outside this enclosing construct; conversely,
it follows from the previous rule that if the target statement is enclosed
by such a construct, then the goto statement cannot be outside.
The execution of a goto statement transfers control to the named target
statement.
Note:
The above rules allow transfer of control to a statement of an enclosing
sequence of statements but not the reverse. Similarly, they prohibit
transfers of control such as between alternatives of a case statement, if
statement, or select statement; between exception handlers; or from an
exception handler of a frame back to the sequence of statements of this
frame.
Example:
<<COMPARE>>
if A(I) < ELEMENT then
if LEFT(I) /= 0 then
I := LEFT(I);
goto COMPARE;
end if;
-- some statements
end if;
References: accept statement 9.5, block statement 5.6, case statement 5.4,
compound statement 5.1, exception handler 11.2, frame 11.2, generic body
12.1, if statement 5.3, label 5.1, package body 7.1, program unit 6, select
statement 9.7, sequence of statements 5.1, statement 5.1, subprogram body
6.3, task body 9.1, transfer of control 5.1